{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Рассказать про домашнее задание__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Семинар 2: чтение из файла и обвязка С++ - проектов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Чтение из файла"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Файл, который будем читать"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 1_intro_file_reading/input.txt\n",
    "21\n",
    "42\n",
    "\n",
    "53"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение из файла в стиле С"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 1_intro_file_reading/main_c.cpp\n",
    "#include <cstdio>\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tFILE* f = std::fopen(\"input.txt\", \"r\");\n",
    "\tif (!f)\n",
    "\t{\n",
    "\t\tstd::puts(\"cannot open file input.txt\");\n",
    "\t\treturn 1;\n",
    "\t}\n",
    "\n",
    "\tint sum = 0;\n",
    "\tint x = 0;\n",
    "\twhile (std::fscanf(f, \"%i\", &x) != EOF)\n",
    "\t\tsum += x;\n",
    "\n",
    "\tstd::printf(\"sum = %i\\n\", sum);\n",
    "\n",
    "\tstd::fclose(f);\n",
    "\n",
    "\treturn 0;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение из файла в стиле C++"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 1_intro_file_reading/main_cpp.cpp\n",
    "#include <fstream>\n",
    "#include <iostream>\n",
    "\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tstd::ifstream ifs(\"input.txt\");\n",
    "\tif (!ifs)\n",
    "\t{\n",
    "\t\tstd::cerr << \"ERROR: cannot open file input.txt\" << std::endl;\n",
    "\t\treturn 1;\n",
    "\t}\n",
    "\n",
    "\tint sum = 0, x = 0;\n",
    "\twhile (ifs >> x)\n",
    "\t\tsum += x;\n",
    "\n",
    "\tstd::cout << sum << std::endl;\n",
    "\n",
    "\treturn 0;\n",
    "}\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение из файла блоками"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 1_intro_file_reading/main_cpp_block.cpp\n",
    "#include <fstream>\n",
    "#include <iostream>\n",
    "#include <vector>\n",
    "\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tstd::ifstream ifs(\"input.txt\");\n",
    "\tif (!ifs)\n",
    "\t{\n",
    "\t\tstd::cerr << \"ERROR: cannot open file\\n\";\n",
    "\t\treturn 1;\n",
    "\t}\n",
    "\n",
    "\tconst unsigned BUFSIZE = 2; \n",
    "\tstd::vector<char> buffer(BUFSIZE);\n",
    "\n",
    "\twhile (true)\n",
    "\t{\n",
    "\t\tifs.read(&buffer[0], buffer.size());\n",
    "\t\tconst unsigned n = ifs.gcount();\n",
    "\t\tif (!n)\n",
    "\t\t\tbreak;\n",
    "\n",
    "\t\tstd::string s(&buffer[0], n);\n",
    "\t\tstd::cout << s;\n",
    "\t}\n",
    "\n",
    "\treturn 0;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скомпилируем вариант С:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.10\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 1_intro_file_reading/main_c.cpp -o read_file_c.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.34\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 1_intro_file_reading/main_cpp.cpp -o read_file_cpp.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.39\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 1_intro_file_reading/main_cpp_block.cpp -o read_file_cpp_block.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Почему такая разница по времени компиляции?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Запустим, проверим как оно работает"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cp 1_intro_file_reading/input.txt ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sum = 116\r\n"
     ]
    }
   ],
   "source": [
    "!./read_file_c.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "116\r\n"
     ]
    }
   ],
   "source": [
    "!./read_file_cpp.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "21\r\n",
      "42\r\n",
      "\r\n",
      "53\r\n"
     ]
    }
   ],
   "source": [
    "!./read_file_cpp_block.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Подчистим за собой"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "!rm -f *.exe input.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### CMake-обвязка над C++ - проектами"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Проштудировать содержимое `2_intro_cmake_and_unittesting`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скрипт сборки:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-- The C compiler identification is GNU 7.4.0\n",
      "-- The CXX compiler identification is GNU 7.4.0\n",
      "-- Check for working C compiler: /usr/bin/cc\n",
      "-- Check for working C compiler: /usr/bin/cc -- works\n",
      "-- Detecting C compiler ABI info\n",
      "-- Detecting C compiler ABI info - done\n",
      "-- Detecting C compile features\n",
      "-- Detecting C compile features - done\n",
      "-- Check for working CXX compiler: /usr/bin/c++\n",
      "-- Check for working CXX compiler: /usr/bin/c++ -- works\n",
      "-- Detecting CXX compiler ABI info\n",
      "-- Detecting CXX compiler ABI info - done\n",
      "-- Detecting CXX compile features\n",
      "-- Detecting CXX compile features - done\n",
      "-- Configuring done\n",
      "-- Generating done\n",
      "-- Build files have been written to: /home/ivafanas/Documents/cpp_shad_students/2019_sem1/seminar2_readfiles_cmake_unittests/build/googletest-download\n",
      "Scanning dependencies of target googletest\n",
      "[ 11%] Creating directories for 'googletest'\n",
      "[ 22%] Performing download step (git clone) for 'googletest'\n",
      "Cloning into 'googletest-src'...\n",
      "Already on 'master'\n",
      "Your branch is up to date with 'origin/master'.\n",
      "[ 33%] No patch step for 'googletest'\n",
      "[ 44%] Performing update step for 'googletest'\n",
      "Current branch master is up to date.\n",
      "[ 55%] No configure step for 'googletest'\n",
      "[ 66%] No build step for 'googletest'\n",
      "[ 77%] No install step for 'googletest'\n",
      "[ 88%] No test step for 'googletest'\n",
      "[100%] Completed 'googletest'\n",
      "[100%] Built target googletest\n",
      "-- Found PythonInterp: /usr/bin/python (found version \"2.7.15\") \n",
      "-- Looking for pthread.h\n",
      "-- Looking for pthread.h - found\n",
      "-- Looking for pthread_create\n",
      "-- Looking for pthread_create - not found\n",
      "-- Looking for pthread_create in pthreads\n",
      "-- Looking for pthread_create in pthreads - not found\n",
      "-- Looking for pthread_create in pthread\n",
      "-- Looking for pthread_create in pthread - found\n",
      "-- Found Threads: TRUE  \n",
      "-- Configuring done\n",
      "-- Generating done\n",
      "-- Build files have been written to: /home/ivafanas/Documents/cpp_shad_students/2019_sem1/seminar2_readfiles_cmake_unittests/build\n",
      "\u001b[35m\u001b[1mScanning dependencies of target explib\u001b[0m\n",
      "[  7%] \u001b[32mBuilding CXX object CMakeFiles/explib.dir/src/explib/solver.cpp.o\u001b[0m\n",
      "[ 15%] \u001b[32mBuilding CXX object CMakeFiles/explib.dir/src/explib/util.cpp.o\u001b[0m\n",
      "[ 23%] \u001b[32m\u001b[1mLinking CXX static library libexplib.a\u001b[0m\n",
      "[ 23%] Built target explib\n",
      "\u001b[35m\u001b[1mScanning dependencies of target exp\u001b[0m\n",
      "[ 30%] \u001b[32mBuilding CXX object CMakeFiles/exp.dir/src/main.cpp.o\u001b[0m\n",
      "[ 38%] \u001b[32m\u001b[1mLinking CXX executable exp\u001b[0m\n",
      "[ 38%] Built target exp\n",
      "\u001b[35m\u001b[1mScanning dependencies of target gtest\u001b[0m\n",
      "[ 46%] \u001b[32mBuilding CXX object googletest-build/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o\u001b[0m\n",
      "[ 53%] \u001b[32m\u001b[1mLinking CXX static library ../../lib/libgtest.a\u001b[0m\n",
      "[ 53%] Built target gtest\n",
      "\u001b[35m\u001b[1mScanning dependencies of target gtest_main\u001b[0m\n",
      "[ 61%] \u001b[32mBuilding CXX object googletest-build/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o\u001b[0m\n",
      "[ 69%] \u001b[32m\u001b[1mLinking CXX static library ../../lib/libgtest_main.a\u001b[0m\n",
      "[ 69%] Built target gtest_main\n",
      "\u001b[35m\u001b[1mScanning dependencies of target exp_unittests\u001b[0m\n",
      "[ 76%] \u001b[32mBuilding CXX object CMakeFiles/exp_unittests.dir/src/tests/main.cpp.o\u001b[0m\n",
      "[ 84%] \u001b[32mBuilding CXX object CMakeFiles/exp_unittests.dir/src/tests/util_unittest.cpp.o\u001b[0m\n",
      "[ 92%] \u001b[32mBuilding CXX object CMakeFiles/exp_unittests.dir/src/tests/solver_unittest.cpp.o\u001b[0m\n",
      "[100%] \u001b[32m\u001b[1mLinking CXX executable exp_unittests\u001b[0m\n",
      "[100%] Built target exp_unittests\n"
     ]
    }
   ],
   "source": [
    "!rm -rf build && mkdir build && cd build && cmake ../2_intro_cmake_and_unittesting/exp && cmake --build ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Содержимое папки build:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bin\t\tcmake_install.cmake  googletest-build\t  lib\r\n",
      "CMakeCache.txt\texp\t\t     googletest-download  libexplib.a\r\n",
      "CMakeFiles\texp_unittests\t     googletest-src\t  Makefile\r\n"
     ]
    }
   ],
   "source": [
    "!ls build"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Прогоним тесты:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;32m[==========] \u001b[mRunning 4 tests from 2 test suites.\r\n",
      "\u001b[0;32m[----------] \u001b[mGlobal test environment set-up.\r\n",
      "\u001b[0;32m[----------] \u001b[m2 tests from calc_exp\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mcalc_exp.the_first_num\r\n",
      "\u001b[0;32m[       OK ] \u001b[mcalc_exp.the_first_num (0 ms)\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mcalc_exp.high_order_value\r\n",
      "/home/ivafanas/Documents/cpp_shad_students/2019_sem1/seminar2_readfiles_cmake_unittests/2_intro_cmake_and_unittesting/exp/src/tests/util_unittest.cpp:14: Failure\r\n",
      "Expected equality of these values:\r\n",
      "  2.7181\r\n",
      "  calc_exp(50)\r\n",
      "    Which is: 2.69159\r\n",
      "\u001b[0;31m[  FAILED  ] \u001b[mcalc_exp.high_order_value (0 ms)\r\n",
      "\u001b[0;32m[----------] \u001b[m2 tests from calc_exp (0 ms total)\r\n",
      "\r\n",
      "\u001b[0;32m[----------] \u001b[m2 tests from read_n\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mread_n.correct_value\r\n",
      "\u001b[0;32m[       OK ] \u001b[mread_n.correct_value (0 ms)\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mread_n.incorrect_value\r\n",
      "\u001b[0;32m[       OK ] \u001b[mread_n.incorrect_value (0 ms)\r\n",
      "\u001b[0;32m[----------] \u001b[m2 tests from read_n (0 ms total)\r\n",
      "\r\n",
      "\u001b[0;32m[----------] \u001b[mGlobal test environment tear-down\r\n",
      "\u001b[0;32m[==========] \u001b[m4 tests from 2 test suites ran. (0 ms total)\r\n",
      "\u001b[0;32m[  PASSED  ] \u001b[m3 tests.\r\n",
      "\u001b[0;31m[  FAILED  ] \u001b[m1 test, listed below:\r\n",
      "\u001b[0;31m[  FAILED  ] \u001b[mcalc_exp.high_order_value\r\n",
      "\r\n",
      " 1 FAILED TEST\r\n"
     ]
    }
   ],
   "source": [
    "!build/exp_unittests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Подчистим"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "!rm -rf build"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Юнит-тесты"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Контракты функции:\n",
    "  * предусловие (precondition / expect)\n",
    "  * постусловие (postcondition / ensure)\n",
    "  * инвариант (precondition + postcondition / invariant)\n",
    "  * утверждение (assertion)\n",
    "\n",
    "\n",
    "Приведите примеры контрактов (exception-ы исключаем из рассмотрения, \"сейчас про них ничего не знаем\"):\n",
    "\n",
    "```c++\n",
    "double sqrt(double x);\n",
    "bool binary_search(int *arr, int n, int value);\n",
    "unsigned read_n(std::istream& is);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Типы функциональных тестов:\n",
    "* позитивный сценарий\n",
    "* негативный сценарий\n",
    "* граничные условия\n",
    "\n",
    "Приведите примеры тестов на функции `sqrt`, `binary_search`, `read_n`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для упражнения напишем тесты на функцию, считающую длину ломаной"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 3_unittests_practices/polyline.h\n",
    "#pragma once\n",
    "\n",
    "#include <vector>\n",
    "\n",
    "struct Point\n",
    "{\n",
    "\tfloat x;\n",
    "\tfloat y;\n",
    "};\n",
    "\n",
    "float get_polyline_len(const std::vector<Point>& polyline);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 3_unittests_practices/polyline.cpp\n",
    "#include \"polyline.h\"\n",
    "\n",
    "#include <cmath>\n",
    "\n",
    "float get_polyline_len(const std::vector<Point>& polyline)\n",
    "{\n",
    "    float rv = 0;\n",
    "    for (int i = 1; i < polyline.size(); ++i)\n",
    "    {\n",
    "        const Point prev = polyline[i - 1];\n",
    "        const Point curr = polyline[i];\n",
    "        const float dx = curr.x - prev.x;\n",
    "        const float dy = curr.y - prev.y;\n",
    "        rv += std::sqrt(dx * dx + dy * dy);\n",
    "    }\n",
    "    return rv;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# %load 3_unittests_practices/polyline_unittests.cpp\n",
    "#include \"gtest/gtest.h\"\n",
    "\n",
    "#include \"polyline.h\"\n",
    "\n",
    "// alias for shorter code\n",
    "using Polyline = std::vector<Point>;\n",
    "\n",
    "\n",
    "TEST(get_polyline_len, empty_polyline)\n",
    "{\n",
    "\tPolyline empty_poly;\n",
    "\tconst double len = get_polyline_len(empty_poly);\n",
    "\tEXPECT_EQ(0, len);\n",
    "}\n",
    "\n",
    "TEST(get_polyline_len, single_point_polyline)\n",
    "{\n",
    "\tPolyline poly{{1,1}};\n",
    "\tconst double len = get_polyline_len(poly);\n",
    "\tEXPECT_EQ(0, len);\n",
    "}\n",
    "\n",
    "TEST(get_polyline_len, single_segment_polyline)\n",
    "{\n",
    "\tPolyline poly{{1,1}, {1, 2}};\n",
    "\tconst double len = get_polyline_len(poly);\n",
    "\tEXPECT_EQ(1, len);\n",
    "}\n",
    "\n",
    "TEST(get_polyline_len, std_polyline)\n",
    "{\n",
    "\tPolyline poly{{1,1}, {1, 2}, {2, 2}};\n",
    "\tconst double len = get_polyline_len(poly);\n",
    "\tEXPECT_EQ(2, len);\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
